package com.h3bpm.web.controller;

import OThinker.Common.Data.ArrayConvertor;
import OThinker.Common.Data.Database.Parameter;
import OThinker.Common.Data.DbType;
import OThinker.Common.DateTimeUtil;
import OThinker.Common.DotNetToJavaStringHelper;
import OThinker.Common.TimeSpan;
import OThinker.H3.Controller.ControllerBase;
import OThinker.H3.Controller.ViewModels.ActionResult;
import OThinker.H3.Controller.ViewModels.InstanceViewModel;
import OThinker.H3.Entity.Instance.InstanceContext;
import OThinker.H3.Entity.Instance.InstanceState;
import OThinker.H3.Entity.WorkItem.WorkItemModels.WorkItem;
import OThinker.H3.Entity.WorkflowTemplate.WorkflowClause;
import com.h3bpm.base.model.GridViewModel;
import com.h3bpm.base.model.PagerInfo;
import data.DataException;
import data.DataRow;
import data.DataTable;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 工作任务服务类

 */
@Controller
@RequestMapping(value="/Portal/Instance")
public class ExtendInstanceController extends ControllerBase {

    private static final Logger logger = LoggerFactory.getLogger(ExtendInstanceController.class);
    /**
     查询流程实例

     @param pagerInfo/Portal/InstanceDetail/GetInstanceStateInfo
     @param searchKey
     @param workflowCode
     @param unitID
     @param startTime
     @param endTime
     @param instaceState
     @return
      * @throws Exception
     * update by zhangj 同步.NET代码
     */
    @RequestMapping(value="/QueryInstanceNew",method={RequestMethod.GET,RequestMethod.POST})
    @ResponseBody
    public final Object QueryInstance(PagerInfo pagerInfo, String searchKey, String workflowCode,
                                      String unitID, String startTime, String endTime, int instaceState, String sequenceNo) throws Exception{
        //添加关键词搜索条件
        //查询流程
        List<InstanceViewModel> griddata = new ArrayList<InstanceViewModel>();
        GridViewModel<InstanceViewModel> result = new GridViewModel<InstanceViewModel>(0, griddata, pagerInfo.getsEcho());

        //add by luwei@Future 2018.8.10 sql防注入
        searchKey = StringEscapeUtils.escapeSql(searchKey);
        workflowCode = StringEscapeUtils.escapeSql(workflowCode);

        String[] Originators;
        if(StringUtils.isNotBlank(unitID)) {
            Originators = unitID.split(",");
        }else{
            Originators = null;
        }

        //权限控制
        if(null == Originators){
            ActionResult actionResult = this.GetQueryAcl(workflowCode, unitID);
            if (!actionResult.getSuccess()) {
                result.setExtendProperty(actionResult);
                return result;
            }
        }else {
            for (String item : Originators) {
                ActionResult actionResult = this.GetQueryAcl(workflowCode, item);
                if (!actionResult.getSuccess()) {
                    actionResult.setExtend("没有权限" + item);
                    result.setExtendProperty(actionResult);
                    return result;
                }
            }
        }
        //拆分组织和用户
        List<String>users = new ArrayList<>();
        List<String>orgList = new ArrayList<>();
        if(null != Originators){
            for (String item : Originators) {
                //获取组织及其所有子节点
                List<String>childOrg = getAllChildAndCurrentOrg(item);
                if(childOrg.isEmpty()){
                    //用户
                    users.add(item);
                }else {
                    orgList.addAll(childOrg);
                }
            }
        }

        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        // 记录总数
        InstanceState state = this.GetInstanceState(instaceState);

        List<Parameter> params = new ArrayList<>();
        String[] conditions = GetQueryInstanceConditions(
                params,
                users.isEmpty() ? null : users.toArray(new String[users.size()]),
                workflowCode,
                state,
                startTime == null||startTime.isEmpty() ? DateTimeUtil.minValue() : df.parse(startTime),
                endTime == null||endTime.isEmpty() ? DateTimeUtil.maxValue() : DateTimeUtil.getDatePlusOne(df.parse(endTime)),
                sequenceNo,
                orgList.isEmpty() ? null : orgList.toArray(new String[orgList.size()]));

        if (!DotNetToJavaStringHelper.isNullOrEmpty(searchKey))
        {
            //查询关键字按流程名称查询，不按流水号查询
            String searchKeyCondition = "(" + InstanceContext.TableName + "." + InstanceContext.PropertyName_InstanceName + " LIKE ?)";
            Object[] objs = ArrayConvertor.AddToArray(conditions, searchKeyCondition);
            conditions = new String[objs.length];
            for (int i = 0; i < objs.length; i++) {
                conditions[i] = (String)objs[i];
            }

            params.add(new Parameter(
                    InstanceContext.TableName + "." + InstanceContext.PropertyName_InstanceName,
                    DbType.String,
                    "%"+searchKey.replace("'", "''")+"%"));
        }

        DataTable dtInstance = getEngine().getPortalQuery().QueryInstance(params, conditions, pagerInfo.getStartIndex(), pagerInfo.getEndIndex());
        //update by zhangj
        dtInstance = this.GetParticipant(dtInstance);
        int total = getEngine().getPortalQuery().CountInstance(params, conditions);

        String[] columns = new String[] { WorkItem.PropertyName_OrgUnit };
        griddata = this.Getgriddata(dtInstance, columns);
        result = new GridViewModel<InstanceViewModel>(total, griddata, pagerInfo.getsEcho());

        return result;
    }

    /**
     * 获取当前组织所有子节点和自己
     * @param orgId
     */
    private List<String> getAllChildAndCurrentOrg(String orgId) throws DataException {
        String sql = "SELECT ObjectID from ot_organizationunit where FIND_IN_SET(ObjectID,getChildrenOrg('%s'));";
        DataTable dataTable = getEngine().getQuery().QueryTable(String.format(sql, orgId));
        List<String>childOrg = new ArrayList<>();
        if (dataTable != null && dataTable.getRows().size()>0) {
            for (int i = 0; i < dataTable.getRows().size(); i++) {
                String ObjectID = dataTable.getRows().get(i).getString("ObjectID");
                childOrg.add(ObjectID);
            }
        }
        logger.info("查询到节点数： {}",childOrg.size());
        return childOrg;
    }

    // FIXME ousf 20181028 增加GroupIn函数，用于SQL预编译处理
    public static String GroupIn(String ColumnName, String[] Values) {
        if(Values == null) {
            return null;
        } else if(Values.length == 0) {
            return "1=2";
        } else if(Values.length == 1) {
            return Values[0] == null?ColumnName + " is null":ColumnName + "=?";
        } else {
            StringBuilder builder = new StringBuilder();
            String[] var6 = Values;
            int var5 = Values.length;

            for(int var4 = 0; var4 < var5; ++var4) {
                String v = var6[var4];
                if(builder.length() != 0) {
                    builder.append(", ");
                }

                if(v == null) {
                    builder.append("null");
                } else {
                    builder.append("?");
                }
            }

            builder.insert(0, ColumnName + " IN (");
            builder.append(")");
            return builder.toString();
        }
    }

    public final String[] GetQueryInstanceConditions(List<Parameter> params, String[] users, String WorkflowCode,
                                                     InstanceState InstanceState, Date CreatedTime_From, Date CreatedTime_To, String sequenceNo, String[] orgs) {
        //封装用户参数
        if(null != users){
            for (int i=0; i<users.length; i++){
                if(null == users[i]) continue;
                params.add(new Parameter(InstanceContext.PropertyName_Originator, DbType.String, users[i]));
            }
        }
        //封装组织参数
        if(null != orgs){
            for (int i=0; i<orgs.length; i++){
                if(null == orgs[i]) continue;
                params.add(new Parameter(InstanceContext.PropertyName_OrgUnit, DbType.String, orgs[i]));
            }
        }

        String[] conditions = new String[]{
                (users == null ? null : GroupIn(InstanceContext.PropertyName_Originator, users)),
                getWorkflowCodeCondition(WorkflowCode, params),
                BuildState(InstanceState, true),
                ((CreatedTime_From.equals(DateTimeUtil.minValue())||CreatedTime_From.equals(DateTimeUtil.maxValue()))?null: (InstanceContext.PropertyName_CreatedTime + "> ?" )),
                ((CreatedTime_To.equals(DateTimeUtil.minValue())||CreatedTime_To.equals(DateTimeUtil.maxValue()))?null:(InstanceContext.PropertyName_CreatedTime + "<=?" )),
                getSequenceNoCondition(sequenceNo, params),
                (orgs == null ? null : GroupIn(InstanceContext.PropertyName_OrgUnit, orgs))};

        if(!(CreatedTime_From.equals(DateTimeUtil.minValue())||CreatedTime_From.equals(DateTimeUtil.maxValue()))){
            params.add(new Parameter(InstanceContext.PropertyName_CreatedTime, DbType.Date,CreatedTime_From));
        }
        if(!(CreatedTime_To.equals(DateTimeUtil.minValue())||CreatedTime_To.equals(DateTimeUtil.maxValue()))){
            params.add(new Parameter(InstanceContext.PropertyName_CreatedTime, DbType.Date,CreatedTime_To));
        }
        return conditions;
    }

    private String getSequenceNoCondition(String sequenceNo, List<Parameter> params){
        String condition = null;
        if (StringUtils.isNotBlank(sequenceNo)) {
            condition = InstanceContext.TableName + "." + InstanceContext.PropertyName_SequenceNo + "=?";
            params.add(new Parameter(InstanceContext.PropertyName_SequenceNo, DbType.String, sequenceNo));
        }
        return condition;
    }

    //add by luwei
    // FIXME ousf 20181027 增加List<Parameter> params参数
    private String getWorkflowCodeCondition(String WorkflowCodes, List<Parameter> params) {
        String workflowCodeCondition = null;
        if (StringUtils.isNotBlank(WorkflowCodes)) {
            if (WorkflowCodes.contains(",")) {
                String[] workflowCodes = WorkflowCodes.split(",");
                int length = workflowCodes.length;
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < length; i++) {
                    String code = workflowCodes[i];
                    if (StringUtils.isNotBlank(code)) {
//    					sb.append("'").append(code).append("'");
                        sb.append("?");
                        if (i != length - 1) {
                            sb.append(",");
                        }
                        params.add(new Parameter(InstanceContext.PropertyName_WorkflowCode, DbType.String, code));
                    }
                }
                if (sb.length() > 0) {
                    workflowCodeCondition = String.format("OT_InstanceContext.WorkflowCode in (%s)", sb.toString());
                }
            } else {
                //workflowCodeCondition = InstanceContext.TableName + "." + InstanceContext.PropertyName_WorkflowCode + "='" + WorkflowCodes + "'";
                workflowCodeCondition = InstanceContext.TableName + "." + InstanceContext.PropertyName_WorkflowCode + "=?";
                params.add(new Parameter(InstanceContext.PropertyName_WorkflowCode, DbType.String, WorkflowCodes));
            }
        }
        return workflowCodeCondition;
    }


    private static String BuildState(InstanceState InstanceState)
    {
        return BuildState(InstanceState, true);
    }
    /**
     * 如果输入为Initiated、Starting:、Running、Finishing或者Finished，那么安装这些状态进行查找
     * 如果输入为Exceptional，则检索Exceptional == true
     * 如果输入为Suspended，则检索Suspended == true
     * 如果输入为Unfinished，则检索State != Finished && State != Canceled
     * 如果输入为Canceled，则检索State == Canceled
     * 如果输入为Unspecified，则无检索条件
     *
     * @param InstanceState 流程状态
     * @param AddTableName
     * @return SQL语句中的条件
     */
    private static String BuildState(InstanceState InstanceState, boolean AddTableName)
    {
        switch (InstanceState)
        {
            case Initiated:
            case Starting:
            case Running:
            case Finishing:
            case Finished:
            case Canceled:
                return (AddTableName ? (InstanceContext.TableName + ".") : null) + InstanceContext.PropertyName_State + "=" + InstanceState.getValue();
            case Exceptional:
                // 如果输入为Exceptional状态，那么检索Exceptional属性是否为true
                return (AddTableName ? (InstanceContext.TableName + ".") : null) + InstanceContext.PropertyName_Exceptional + "=" + 1;
            case Suspended:
                // 如果输入为Suspended状态，那么检索Suspended属性是否为true
                return (AddTableName ? (InstanceContext.TableName + ".") : null) + InstanceContext.PropertyName_Suspended + "=" + 1;
            case Unfinished:
                return (AddTableName ? (InstanceContext.TableName + ".") : null) + InstanceContext.PropertyName_State + "!=" + OThinker.H3.Entity.Instance.InstanceState.Finished.getValue() + " AND " + (AddTableName ? (InstanceContext.TableName + ".") : null) + InstanceContext.PropertyName_State + "!=" + OThinker.H3.Entity.Instance.InstanceState.Canceled.getValue();
            case NotCanceled:
                return (AddTableName ? (InstanceContext.TableName + ".") : null) + InstanceContext.PropertyName_State + "!=" + OThinker.H3.Entity.Instance.InstanceState.Canceled.getValue();
            case Unspecified:
                return null;
            default:
                throw new NotImplementedException();
        }
    }

    /**
     * @Title: GetParticipant
     * @Description: 根据查询流程实例表，获取审批环节，审批人，审批人所属组织
     * @Param: @param dtInstance
     * @Param: @return
     * @Param: @throws Exception
     * @Return: DataTable
     * @throws
     */
    //update by linwp@Future modify static to be final
    public final DataTable GetParticipant(DataTable dtInstance) throws Exception {
        if (dtInstance.getRows().size() == 0){
            return dtInstance;
        }
        List<String> instanceID = new ArrayList<String>();
        for (int i = 0; i < dtInstance.getRows().size(); i++){
            DataRow row = dtInstance.getRows().get(i);

            instanceID.add(row.getString(WorkItem.PropertyName_ObjectID));
        }
        DataTable dtWorkItem = getEngine().getPortalQuery().GetActiveNamebyInstanceId(instanceID);
        //获取审批人所属组织的集合 update by Lee 2018-12-04 增加获取代理人集合
        Map<String, String> ParticipantOuDept = GetUnitNamesFromTable(dtWorkItem, new String[] { WorkItem.PropertyName_Participant });

        //update by Lee 2018-12-04 增加获取代理人集合
        Map<String, String> delegantMap = GetUnitNamesFromTable(dtWorkItem, new String[] { WorkItem.PropertyName_Delegant });

        //获取流程实例的当前审批环节,审批人,审批人所属组织
        Map<String, String> ApproverLink = new HashMap<String, String>();
        Map<String, String> Approver = new HashMap<String, String>();
        Map<String, String> ApproverOuDept = new HashMap<String, String>();
        //add by linwp@Future
        Map<String, String> ApproverReceivedTime = new HashMap<String, String>();
        for (int i = 0; i< dtWorkItem.getRows().size(); i++){
            DataRow row = dtWorkItem.getRows().get(i);

            String instanceid = (row.getString(WorkItem.PropertyName_InstanceId) + "").trim();
            String approverlink = (!"".equals((row.getString(WorkItem.PropertyName_DisplayName) + "")) ?(row.getString(WorkItem.PropertyName_DisplayName) + "") : (row.getString(WorkItem.PropertyName_ActivityCode) + "")).trim();
            String participantname = (row.getString(WorkItem.PropertyName_ParticipantName) + "").trim();
            //update by Lee 2018-12-04 增加代理人判断，如果有代理人则显示代理人。
            String delegantName = GetValueFromDictionary(delegantMap,row.getString(WorkItem.PropertyName_Delegant));
            if(!DotNetToJavaStringHelper.isNullOrEmpty(delegantName)){
                participantname = delegantName + "[" + "来自" + participantname + "的委托" + "]";
            }
            String participantOUname = GetValueFromDictionary(ParticipantOuDept, row.getString(WorkItem.PropertyName_Participant) + "");
            //add by linwp@Future
            String receivedTime =  (row.getString(WorkItem.PropertyName_ReceiveTime) + "").trim();
            //审批人
            if (Approver.containsKey(instanceid)) {
                if(Approver.get(instanceid).indexOf(participantname) == -1){
                    Approver.put(instanceid, Approver.get(instanceid) + "," + participantname);
                }
            } else {
                Approver.put(instanceid, participantname);
            }
            //审批环节
            if (ApproverLink.containsKey(instanceid)) {
                if(ApproverLink.get(instanceid).indexOf(approverlink) == -1){
                    ApproverLink.put(instanceid, ApproverLink.get(instanceid) + "," + approverlink);
                }
            } else {
                ApproverLink.put(instanceid, approverlink);
            }
            //审批人所属组织
            if (ApproverOuDept.containsKey(instanceid)) {
                //update by zhangj
                if(ApproverOuDept.get(instanceid) != null && ApproverOuDept.get(instanceid).indexOf(participantOUname) == -1){
                    ApproverOuDept.put(instanceid, ApproverOuDept.get(instanceid) + "," + participantOUname);
                }
            } else {
                ApproverOuDept.put(instanceid, participantOUname);
            }
            //add by linwp@Future
            if (ApproverReceivedTime.containsKey(instanceid)) {
                if(ApproverReceivedTime.get(instanceid) != null && ApproverReceivedTime.get(instanceid).indexOf(receivedTime) == -1){
                    ApproverReceivedTime.put(instanceid, ApproverReceivedTime.get(instanceid) + "," + receivedTime);
                }
            } else {
                ApproverReceivedTime.put(instanceid, receivedTime);
            }
        }

        if (dtWorkItem.getRows().size() > 0) {
            for (int i = 0; i < dtInstance.getRows().size(); i++) {
                DataRow row = dtInstance.getRows().get(i);
                try {
                    String instanceid = row.getString(InstanceContext.PropertyName_ObjectID) + "";
                    row.setString("Approver", Approver.get(instanceid));
                    row.setString("ApproverLink", ApproverLink.get(instanceid));
                    row.setString("ApproverOuDept", ApproverOuDept.get(instanceid));
                    //add by linwp@Future
                    row.setString("ApproverReceivedTime", ApproverReceivedTime.get(instanceid));
                }
                catch (java.lang.Exception e)
                {

                }
            }
        }
        return dtInstance;

    }

    /**
     * 获取返回到前端的InstanceViewModel
     *
     * @param dtInstance
     * @param columns
     * @return
     * @throws DataException
     * @throws Exception
     */
    //update by liwnp@Future modify static to be final
    public final  List<InstanceViewModel> Getgriddata(DataTable dtInstance, String[] columns) throws DataException, Exception
    {
        Map<String, String> unitNames = GetUnitNamesFromTable(dtInstance, columns);
        List<InstanceViewModel> griddata = new ArrayList<InstanceViewModel>();
        for (int i = 0; i < dtInstance.getRows().size(); i++)
        {
            DataRow row = dtInstance.getRows().get(i);

            InstanceViewModel tempVar = new InstanceViewModel();
            tempVar.setPriority(row.getString(InstanceContext.PropertyName_Priority));
            tempVar.setInstanceID(row.getString(InstanceContext.PropertyName_InstanceId));
            tempVar.setInstanceName(row.getString(InstanceContext.PropertyName_InstanceName));
            tempVar.setWorkflowName(row.getString(WorkflowClause.PropertyName_WorkflowName));
            tempVar.setWorkflowCode(row.getString(InstanceContext.PropertyName_WorkflowCode));
            tempVar.setOriginator(row.getString(InstanceContext.PropertyName_Originator));
            tempVar.setOriginatorName(row.getString(InstanceContext.PropertyName_OriginatorName));
            tempVar.setOriginatorOUName(GetValueFromDictionary(unitNames, row.getString(InstanceContext.PropertyName_OrgUnit)));
            tempVar.setInstanceState(row.getString(InstanceContext.PropertyName_State));
            //tempVar.setCreatedTime(DateTimeUtil.getDateTimeToString(row.getDate(InstanceContext.PropertyName_CreatedTime)));
            tempVar.setCreatedTime(GetValueFromDate(row.getObject(InstanceContext.PropertyName_CreatedTime), WorkItemTimeFormat));
            tempVar.setPlanFinishTime(DateTimeUtil.getDateTimeToString(row.getDate(InstanceContext.PropertyName_PlanFinishTime)));
            tempVar.setFinishedTime(DateTimeUtil.getDateTimeToString(row.getDate(InstanceContext.PropertyName_FinishTime)));
            tempVar.setstayTime(TimeSpan.Subtract(new Date(), GetTime(row.getString(InstanceContext.PropertyName_PlanFinishTime))));
            tempVar.setApproverLink(row.getString("ApproverLink"));
            tempVar.setApprover(row.getString("Approver"));
            tempVar.setApproverOuDept(row.getString("ApproverOuDept"));
            //add by linwp@Future 2018.8.3
            tempVar.setReceivedTime(row.getString("ApproverReceivedTime"));
            tempVar.setInstanceSequenceNo(row.getString(InstanceContext.PropertyName_SequenceNo));
            griddata.add(tempVar);
        }
        return griddata;
    }

    /**
     获取查询流程的状态

     @param value
     @return
     */
    public final InstanceState GetInstanceState(Integer value){
        InstanceState state = InstanceState.Unspecified;

        if(value==null){
            return state;
        }

        switch (value){
            case 0:
                state = InstanceState.Unfinished;
                break;
            case 1:
                state = InstanceState.Finished;
                break;
            case 2:
                state = InstanceState.Canceled;
                break;
            default:
                state = InstanceState.Unspecified;
                break;
        }

        return state;
    }

    @Override
    public String getFunctionCode() {
        return null;
    }
}
